package com.czmh.etc.onlinepubsys.utils.ue;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.czmh.etc.onlinepubsys.constants.ue.BusinessType;
import com.czmh.etc.onlinepubsys.enums.ue.ApiCodeEnum;
import com.czmh.etc.onlinepubsys.response.ue.ApiResponse;
import com.czmh.etc.onlinepubsys.utils.RedisUtil;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Component
@Slf4j
public class UeHttpUtil {

    public static String url;
    public static String appKey;
    public static String publicKey;
    public static String secreKey;


    @Value("${ue.url}")
    private String url0;
    @Value("${ue.appKey}")
    private String appKey0;
    @Value("${ue.publicKey}")
    private String publicKey0;
    @Value("${ue.secreKey}")
    private String secreKey0;

    @Autowired
    private RedisUtil redisUtil;

    @PostConstruct
    public void init() {
        url = url0;
        appKey = appKey0;
        publicKey = publicKey0;
        secreKey = secreKey0;
    }

    /**
     * 获取签名
     *
     * @param jsonObject
     * @param publicKey
     * @return
     */
    private static String getSignature(JSONObject jsonObject, String publicKey) {
        if (jsonObject != null) {
            //将JSON字符串转为16进制 解决中文字符占位问题
            String content = RSACryptography.str2HexStr(jsonObject.toJSONString());
            try {
                //加密字符串
                String sign = RSACryptography.encryptByPublicKey(content, (RSAPublicKey) RSACryptography.getPublicKey(publicKey));
                return sign;
            } catch (Exception e) {
                e.printStackTrace();
                log.info("联合电子请求参数加密失败");
                throw new RuntimeException("请求参数加密失败,请联系管理员！");
            }
        } else {
            return null;
        }
    }

    /**
     * 获取授权
     *
     * @param method
     * @param reqData
     * @return
     */
    public static ApiResponse postToken(String method, Map<String, String> reqData) {
        String params = JSON.toJSONString(reqData);
        log.info("联合电子业务号:{}, 参数:{}", method + "--" + getBusinessNote(method), params);
        ApiResponse result = null;
        try {
            // 响应模型
            @Cleanup
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            // 创建Post请求
            HttpPost httpPost = new HttpPost(url + method);
            String timestamp = String.valueOf(System.currentTimeMillis());
            String signature = DigestUtils.sha256Hex(timestamp + "&" + appKey + "&" + secreKey);
            List<NameValuePair> param = new ArrayList<>();
            param.add(new BasicNameValuePair("timestamp", timestamp));
            param.add(new BasicNameValuePair("appKey", appKey));
            param.add(new BasicNameValuePair("signature", signature));

            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(param, "UTF-8");
            httpPost.setEntity(entity);
            RequestConfig config = RequestConfig.custom().setSocketTimeout(60000)
                    .setConnectTimeout(60000).build();
            httpPost.setConfig(config);

            // 由客户端执行(发送)Post请求
            @Cleanup
            CloseableHttpResponse response = httpClient.execute(httpPost);

            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();

            if (responseEntity != null && response.getStatusLine().getStatusCode() == 200) {
                String text = EntityUtils.toString(responseEntity);
                log.info("联合电子业务号:{},响应:{}", method + "--" + getBusinessNote(method), text);
                result = JSON.parseObject(text, ApiResponse.class);
                result.setRspData(text);
            }
            return result;
        } catch (SocketTimeoutException exception) {
            log.error("联合电子请求超时", exception);
            ApiResponse r = new ApiResponse();
            r.setCode(ApiCodeEnum.SOCKET_TIME_OUT.getCode());
            r.setMsg(ApiCodeEnum.SOCKET_TIME_OUT.getMessage());
            return r;
        } catch (SocketException exception) {
            log.error("联合电子连接失败", exception);
            ApiResponse r = new ApiResponse();
            r.setCode(ApiCodeEnum.CONNECTION_REST.getCode());
            r.setMsg(ApiCodeEnum.CONNECTION_REST.getMessage());
            return r;
        } catch (Exception e) {
            log.error("联合电子请求失败", e);
            throw new RuntimeException(e);
        }
    }


    public static ApiResponse post(String method, String reqData, String token) {
        JSONObject jsonObject = JSON.parseObject(reqData);

        //统一处理配置信息
        if (jsonObject.containsKey("appKey")) {
            jsonObject.put("appKey", appKey);
        }
        if (jsonObject.containsKey("appkey")) {
            jsonObject.put("appkey", appKey);
        }
        if (jsonObject.containsKey("reqFrom")) {
            jsonObject.put("reqFrom", "74");
        }
        if (jsonObject.containsKey("reqfrom")) {
            jsonObject.put("reqfrom", "74");
        }
        if (jsonObject.containsKey("qzFlag")) {
            jsonObject.put("qzFlag", "1");
        }


        // 请求参数的签名串-图片上传不加密
        if (!method.equalsIgnoreCase(BusinessType.UPLOAD_PHOTO)) {
            log.info("联合电子业务号:{}, 参数:{}", method + "--" + getBusinessNote(method), jsonObject.toJSONString());
            jsonObject.put("sign", getSignature(jsonObject, publicKey));
        } else {
            //uploadphoto接口时，appkey单独传为000U0000001，不限制200k
            if (jsonObject.containsKey("appKey")) {
                jsonObject.put("appKey", "000U0000001");
            }
            if (jsonObject.containsKey("appkey")) {
                jsonObject.put("appkey", "000U0000001");
            }
        }
        // 平台分配的接入方的唯一标识
        jsonObject.put("publicKey", publicKey);

        ApiResponse result = null;
        //判断授权token是否存在
        if (token == null) {
            ApiResponse r = new ApiResponse();
            r.setCode(ApiCodeEnum.TOKEN_FAIL.getCode());
            r.setMsg(ApiCodeEnum.TOKEN_FAIL.getMessage());
            return r;
        }
        try {
            // 响应模型
            @Cleanup
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            // 创建Post请求
            HttpPost httpPost = new HttpPost(url + method);
            //配置token
            httpPost.setHeader("X-Access-Token", token);

            List<NameValuePair> param = new ArrayList<>();


            //循环填充请求参数
            if (jsonObject != null) {
                Object[] keys = jsonObject.keySet().toArray();
                if (keys != null && keys.length > 0) {
                    for (int i = 0; i < keys.length; i++) {
                        param.add(new BasicNameValuePair(keys[i].toString(), jsonObject.getString(keys[i].toString())));
                    }
                }
            }


            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(param, "UTF-8");
            httpPost.setEntity(entity);
            RequestConfig config = RequestConfig.custom().setSocketTimeout(60000)
                    .setConnectTimeout(60000).build();
            httpPost.setConfig(config);

            // 由客户端执行(发送)Post请求
            @Cleanup
            CloseableHttpResponse response = httpClient.execute(httpPost);

            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();

            if (responseEntity != null && response.getStatusLine().getStatusCode() == 200) {
                String text = EntityUtils.toString(responseEntity);
                log.info("联合电子业务号:{},响应:{}", method + "--" + getBusinessNote(method), text);
                result = JSON.parseObject(text, ApiResponse.class);
                result.setRspData(text);
            }
            return result;
        } catch (SocketTimeoutException exception) {
            log.error("联合电子请求超时", exception);
            ApiResponse r = new ApiResponse();
            r.setCode(ApiCodeEnum.SOCKET_TIME_OUT.getCode());
            r.setMsg(ApiCodeEnum.SOCKET_TIME_OUT.getMessage());
            return r;
        } catch (SocketException exception) {
            log.error("联合电子连接失败", exception);
            ApiResponse r = new ApiResponse();
            r.setCode(ApiCodeEnum.CONNECTION_REST.getCode());
            r.setMsg(ApiCodeEnum.CONNECTION_REST.getMessage());
            return r;
        } catch (Exception e) {
            log.error("联合电子请求失败", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 不打印日志的请求接口，用于定时任务
     *
     * @param method
     * @param reqData
     * @param token
     * @return
     */
    public static ApiResponse postNoLog(String method, String reqData, String token) {
        JSONObject jsonObject = JSON.parseObject(reqData);
        //统一处理配置信息
        if (jsonObject.containsKey("appKey")) {
            jsonObject.put("appKey", appKey);
        }
        if (jsonObject.containsKey("appkey")) {
            jsonObject.put("appkey", appKey);
        }
        if (jsonObject.containsKey("reqFrom")) {
            jsonObject.put("reqFrom", "74");
        }
        if (jsonObject.containsKey("reqfrom")) {
            jsonObject.put("reqfrom", "74");
        }
        if (jsonObject.containsKey("qzFlag")) {
            jsonObject.put("qzFlag", "1");
        }


        // 请求参数的签名串-图片上传不加密
        if (!method.equalsIgnoreCase(BusinessType.UPLOAD_PHOTO)) {
            //log.info("联合电子业务号:{}, 参数:{}", method + "--" + getBusinessNote(method), jsonObject.toJSONString());
            jsonObject.put("sign", getSignature(jsonObject, publicKey));
        }
        // 平台分配的接入方的唯一标识
        jsonObject.put("publicKey", publicKey);

        ApiResponse result = null;
        //判断授权token是否存在
        if (token == null) {
            ApiResponse r = new ApiResponse();
            r.setCode(ApiCodeEnum.TOKEN_FAIL.getCode());
            r.setMsg(ApiCodeEnum.TOKEN_FAIL.getMessage());
            return r;
        }
        try {
            // 响应模型
            @Cleanup
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            // 创建Post请求
            HttpPost httpPost = new HttpPost(url + method);
            //配置token
            httpPost.setHeader("X-Access-Token", token);

            List<NameValuePair> param = new ArrayList<>();


            //循环填充请求参数
            if (jsonObject != null) {
                Object[] keys = jsonObject.keySet().toArray();
                if (keys != null && keys.length > 0) {
                    for (int i = 0; i < keys.length; i++) {
                        param.add(new BasicNameValuePair(keys[i].toString(), jsonObject.getString(keys[i].toString())));
                    }
                }
            }


            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(param, "UTF-8");
            httpPost.setEntity(entity);
            RequestConfig config = RequestConfig.custom().setSocketTimeout(60000)
                    .setConnectTimeout(60000).build();
            httpPost.setConfig(config);

            // 由客户端执行(发送)Post请求
            @Cleanup
            CloseableHttpResponse response = httpClient.execute(httpPost);

            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();

            if (responseEntity != null && response.getStatusLine().getStatusCode() == 200) {
                String text = EntityUtils.toString(responseEntity);
                //log.info("联合电子业务号:{},响应:{}", method + "--" + getBusinessNote(method), text);
                result = JSON.parseObject(text, ApiResponse.class);
                result.setRspData(text);
            }
            return result;
        } catch (SocketTimeoutException exception) {
            log.error("联合电子请求超时", exception);
            ApiResponse r = new ApiResponse();
            r.setCode(ApiCodeEnum.SOCKET_TIME_OUT.getCode());
            r.setMsg(ApiCodeEnum.SOCKET_TIME_OUT.getMessage());
            return r;
        } catch (SocketException exception) {
            log.error("联合电子连接失败", exception);
            ApiResponse r = new ApiResponse();
            r.setCode(ApiCodeEnum.CONNECTION_REST.getCode());
            r.setMsg(ApiCodeEnum.CONNECTION_REST.getMessage());
            return r;
        } catch (Exception e) {
            log.error("联合电子请求失败", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 检查签名正确性
     *
     * @param jsonObject
     * @return
     */
    private static Boolean check(JSONObject jsonObject) {
        try {
            return AlipaySignature.rsa256CheckContent(jsonObject.getString("biz_response"), jsonObject.getString("sign"), publicKey, "UTF-8");
        } catch (AlipayApiException e) {
            return false;
        }
    }

    /**
     * 根据业务号获取业务描述
     *
     * @param businessType
     * @return
     */
    public static String getBusinessNote(String businessType) {
        if (businessType.equalsIgnoreCase(BusinessType.PARTNER_LOGIN)) {
            return "4.1 认证相关接口";
        } else if (businessType.equalsIgnoreCase(BusinessType.SAVE_ACCOUNT_INFO)) {
            return "4.2.1 用户实名认证";
        } else if (businessType.equalsIgnoreCase(BusinessType.CHECK_VEHICLE)) {
            return "4.2.2车辆办理情况查询接口（2021年7月改动）";
        } else if (businessType.equalsIgnoreCase(BusinessType.SAVE_CAR_INFO)) {
            return "4.2.3新增车辆信息";
        } else if (businessType.equalsIgnoreCase(BusinessType.PRODUCT_DETAIL)) {
            return "4.2.4产品推荐查询";
        } else if (businessType.equalsIgnoreCase(BusinessType.PAY_CHANNEL)) {
            return "4.2.5签约渠道查询";
        } else if (businessType.equalsIgnoreCase(BusinessType.SUBMIT_ORDER)) {
            return "4.2.6订单提交";
        } else if (businessType.equalsIgnoreCase(BusinessType.APPLET_UPDATE_ORDER_USER)) {
            return "4.2.7 订单修改接口（修改申办人资料）";
        } else if (businessType.equalsIgnoreCase(BusinessType.UPDATE_VEHICLE)) {
            return "4.2.8 4.2.8 订单修改接口（修改车辆信息）";
        } else if (businessType.equalsIgnoreCase(BusinessType.CANCEL_ORDER)) {
            return "4.2.10取消订单";
        } else if (businessType.equalsIgnoreCase(BusinessType.GET_ORDER_PAY_STATUS)) {
            return "4.2.12订单状态查询接口（根据订单号）";
        } else if (businessType.equalsIgnoreCase(BusinessType.QUERY_ORDER_BY_VEHICLE)) {
            return "4.2.13订单状态查询接口（根据车牌查）";
        } else if (businessType.equalsIgnoreCase(BusinessType.QUERY_ORDER_LIST_BY_APPKEY)) {
            return "4.2.14.1 订单列表";
        } else if (businessType.equalsIgnoreCase(BusinessType.UPLOAD_PHOTO)) {
            return "4.2.14.4 订单列表";
        } else if (businessType.equalsIgnoreCase(BusinessType.BANK_SIGNED)) {
            return "4.3.1提交银行四要素并获取验证码";
        } else if (businessType.equalsIgnoreCase(BusinessType.BANK_VERIFY)) {
            return "4.3.2校验验证码并确认签约";
        } else if (businessType.equalsIgnoreCase(BusinessType.NO_INSURANCE_ORDER_REVIEW)) {
            return "4.3.3卡签自提接口";
        } else if (businessType.equalsIgnoreCase(BusinessType.REQ_ACTIVE)) {
            return "4.4.1卡签激活申请（产品二发）";
        } else if (businessType.equalsIgnoreCase(BusinessType.OBE_SAM)) {
            return "4.4.2 卡片二发接口";
        } else if (businessType.equalsIgnoreCase(BusinessType.ACT_FINISH)) {
            return "4.4.12激活结果确认接口";
        } else {
            return "";
        }
    }


}
